#ifndef __UDSF_TIMERA_C_
#define __UDSF_TIMERA_C_

#include "app.h"
/*
*   notice:
*   UDSF 同UDF编程：不可调用cstd-lib,只可调用"sdk_ifs_udk_cfg.h"、"sys_api.h"中列出的API函数。
*   UDSF文件内函数均需使用static修饰符，且UDF中以#include "udsf_xxx.c"形式引用
*/


static void udsf_timerA_stop(void){
    TMRA->TACCR0 = 0;
    TMRA->TACTL = 0;
    SYSC->CLK_EN &= ~TMRA_EN_Msk;
    PINMUX->MUX0 = PINMUX->MUX0 & (~(0xF<<(2*4))); // clear gpio0.2
}

static void udsf_timerA_square_wave(uint8_t boot_flag,uint32_t period_us){
    // 使用GPIO0.2 输出方波
    SYSC->CLK_EN |= TMRA_EN_Msk;

    PINMUX->MUX0 = PINMUX->MUX0 | (3<<(4*4));
    PIN_CTRL->UE |= 1<<4;
    PIN_CTRL->RE |= 1<<4;
    //PINMUX->MUX1 = 0;

    uint32_t sys_clk = 40000000;
    if( boot_flag > 0 ){
        sys_clk /= 2;
    }

    TMRA->TACCR0 = (sys_clk/1000000)*period_us/2 - 1;
    TMRA->TACTL = TIM_UP;
    
    TMRA->TACCR2  = (sys_clk/1000000)*period_us/2 - 1;
    TMRA->TACCTL4 = OUT_TOGGLE;
}

static int udsf_timerA_capture_square_wave(uint8_t boot_flag,int total_ms,uint16_t period_half_us,uint8_t cnt,uint8_t error_us )
{
		#define TIMERA_PRINTF_TEST

    SYSC->CLK_EN |= TMRA_EN_Msk;

		// gpio0.0 -> timera input
		PINMUX->MUX0 &= (~(0xF<<(0*4)));
		PINMUX->MUX0 |= (3<<(0*4));

		#define CLK_PER_US_XIP (20)
		#define CLK_PER_US_ROM (40)

		#define PER_CIRCLE_US_XIP (65535/CLK_PER_US_XIP)
		#define PER_CIRCLE_US_ROM (65535/CLK_PER_US_ROM)
	
		uint32_t clk_cnt_us = CLK_PER_US_ROM;
		int us_per_circle = PER_CIRCLE_US_ROM;
		
		if( boot_flag > 0 ){
			clk_cnt_us    = CLK_PER_US_XIP;
			us_per_circle = PER_CIRCLE_US_XIP;
		}

		period_half_us *= clk_cnt_us;
		error_us *= clk_cnt_us;
		
    int ms_cnt = 0;
    int ms_cnt_last = 0;
    int ccr_value_last = 0;
    
    int valid_cnt = 0;

    total_ms = total_ms*1000/us_per_circle; // ms 转为 循环超时次数
		
		#if defined(TIMERA_PRINTF_TEST)
		CSTD_PRINTF("clk cnt %d,clk err %d\n",period_half_us,error_us);
		CSTD_PRINTF("total ms %d\n",total_ms);
		int xx_cnt = 0;
		#endif
		
		int capture_cnt=0;
    TMRA->TACTL   = TIM_STOP;
    TMRA->TAIE    = 0x00; // disable interrupt
    TMRA->TACCTL0 = CAP_EDGE_BOTH | CCIS_CCIxA | CAPTURE_MODE  | 0x10; // capture gpio0.0
    TMRA->TACCTL1 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL2 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL3 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL4 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL5 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL6 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    
    TMRA->TAR     = 0x00;
    TMRA->TAI     = 0xFF;    // clear all interrupt
		TMRA->TACTL   = TIM_UP_HEAD;
    //uint32_t cctl0 = TMRA->TACCTL0;
    while(1){
        if( ms_cnt > total_ms ){
						#if defined(TIMERA_PRINTF_TEST)
						CSTD_PRINTF("timeout,%d,%d\n",ms_cnt,total_ms);
						#endif
            break;
        }

        uint32_t tai_value;
        do{
            if( (tai_value = (TMRA->TAI & 0x81)) != 0 ){
                TMRA->TAI = tai_value;
                break;
            }
        }while(1);
				
        if( tai_value & 0x80 ){
            ms_cnt ++;
        }
														
        if( !(tai_value & 0x1) ){
            continue;
        }

        int ccr_value = TMRA->TACCR0;

				int period_us = 0;
				if( ms_cnt != ms_cnt_last ){
					period_us = 0xffff;
				}
				
				int period_half_clk_cap = period_us + ccr_value - ccr_value_last;
				#if defined(TIMERA_PRINTF_TEST)
				((uint32_t*)BBE_ABUF1_BASE)[xx_cnt++] = period_half_clk_cap;
				#endif
				ccr_value_last = ccr_value;
        ms_cnt_last = ms_cnt;
				if( capture_cnt > 0 ){ 
					if( (period_half_clk_cap > (period_half_us - error_us) )&&
					    (period_half_clk_cap < (period_half_us + error_us) ) )
					{
						valid_cnt++;
						if( valid_cnt >= cnt ){
							break;
						}
					}else{
						#if defined(TIMERA_PRINTF_TEST)
						CSTD_PRINTF("err\n");
						#endif
						break;
					}
				}
				capture_cnt++;
    }

    TMRA->TACTL   = TIM_STOP;
    TMRA->TAI     = 0xff;
    SYSC->CLK_EN &= (~TMRA_EN_Msk);
		
		// gpio0.0 -> gpio
    PINMUX->MUX0 &= (~(0xF<<(0*4)));
    PINMUX->MUX0 |= (0<<(0*4));

		#if defined(TIMERA_PRINTF_TEST)
		for(int i = 1;i<xx_cnt;i++){
			CSTD_PRINTF("xx %d is %d\n",i,((int32_t*)BBE_ABUF1_BASE)[i]);
		}
		CSTD_PRINTF("valid_cnt,%d\n",valid_cnt);
		#endif
		
    if( valid_cnt >= cnt ){
        return valid_cnt;
    }
    
    return -1;
		
		#if defined(TIMERA_PRINTF_TEST)
		#undef TIMERA_PRINTF_TEST
		#endif
}



static int udsf_timerA_capture_square_wave_io4(uint8_t boot_flag,uint16_t period_half_us,uint8_t cnt,uint8_t error_us ) // period_half_us最大300us
{
		//#define TIMERA_PRINTF_TEST

    SYSC->CLK_EN |= TMRA_EN_Msk;

		// gpio0.4 -> timera input
		PINMUX->MUX0 &= (~(0xF<<(4*4)));
		PINMUX->MUX0 |= (3<<(4*4));

		#define CLK_PER_US_XIP (20)
		#define CLK_PER_US_ROM (40)
	
		uint32_t clk_cnt_us = CLK_PER_US_ROM;
		
		if( boot_flag > 0 ){
			clk_cnt_us    = CLK_PER_US_XIP;
		}
		period_half_us *= clk_cnt_us; // 转为clk数
		error_us       *= clk_cnt_us; // 转为clk数
		
    int circle_cnt = 0;
    int circle_cnt_last = 0;
		int circle_cnt_last_update = 0;

    int valid_cnt = 0;
	int circle_period_us = period_half_us*5; // period_half_us最大300us

    int ccr_value_last   = 0;		
		int capture_cnt      = 0;
		
		#if defined(TIMERA_PRINTF_TEST)
		CSTD_PRINTF("circle %d,clk cnt %d,clk err %d\n",circle_period_us,period_half_us,error_us);
		int xx_cnt = 0;
		#endif

    TMRA->TACTL   = TIM_STOP;
    TMRA->TAIE    = 0x00; // disable interrupt
    TMRA->TACCTL0 = CAP_EDGE_FALLING | CCIS_GND | COMPARE_MODE | 0x10; 
    TMRA->TACCTL1 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL2 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL3 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL4 = CAP_EDGE_BOTH |  CCIS_CCIxA | CAPTURE_MODE | 0x10; // capture gpio0.4
    TMRA->TACCTL5 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCTL6 = CAP_EDGE_FALLING | CCIS_GND | CAPTURE_MODE | 0x10;
    TMRA->TACCR0  = circle_period_us;
		
    TMRA->TAR     = 0x00;
    TMRA->TAI     = 0xFF;    // clear all interrupt
		TMRA->TACTL   = TIM_UP;

	int res = -1;
    while(1){
			
			if( circle_cnt > (circle_cnt_last_update+2)  ){ // 连续两次未更新 强制退出
				#if defined(TIMERA_PRINTF_TEST)
				CSTD_PRINTF("timeout\n");
				#endif
				res = -2;
				break;
			}
			
			uint32_t tai_value;
			do{
					if( ((tai_value = TMRA->TAI) & 0x91) != 0 ){
							TMRA->TAI = tai_value;
							break;
					}
			}while(1);
			if( tai_value & 0x81 ){
					circle_cnt ++;
			}
													
			if( !(tai_value & 0x10) ){
					continue;
			}

			int ccr_value = TMRA->TACCR4;

			int period_us = 0;
			if( circle_cnt != circle_cnt_last ){
				period_us = circle_period_us*(circle_cnt_last-circle_cnt);
			}
			int period_half_clk_cap = period_us + ccr_value - ccr_value_last;
			#if defined(TIMERA_PRINTF_TEST)
			((uint32_t*)BBE_ABUF1_BASE)[xx_cnt++] = period_half_clk_cap;
			#endif
			ccr_value_last = ccr_value;
			circle_cnt_last = circle_cnt;
			if( capture_cnt > 0 ){
				if( CSTD_ABS(period_half_clk_cap-period_half_us) < error_us ){
					valid_cnt++;
					if( valid_cnt >= cnt ){
						break;
					}
				}else{
					#if defined(TIMERA_PRINTF_TEST)
					CSTD_PRINTF("err\n");
					#endif
					res = -3;
					break;
				}
			}
			circle_cnt_last_update = circle_cnt;
			capture_cnt++;
	}

	TMRA->TACTL   = TIM_STOP;
	TMRA->TAI     = 0xff;
	SYSC->CLK_EN &= (~TMRA_EN_Msk);
	
	// gpio0.4 -> gpio
	PINMUX->MUX0 &= (~(0xF<<(4*4)));
	PINMUX->MUX0 |= (0<<(4*4));

	#if defined(TIMERA_PRINTF_TEST)
	for(int i = 1;i<xx_cnt;i++){
		CSTD_PRINTF("xx %d is %d\n",i,((int32_t*)BBE_ABUF1_BASE)[i]);
	}
	CSTD_PRINTF("valid_cnt %d\n",valid_cnt);
	#endif
	
	if( valid_cnt >= cnt ){
			return valid_cnt;
	}
	
	return res;
	
	#if defined(TIMERA_PRINTF_TEST)
	#undef TIMERA_PRINTF_TEST
	#endif
}



#endif
